package com.warm.base.design.c_prototype;

/**
 * @Date: 2019/11/21 17:15
 * @Author: LChuang
 * @Description: 原型模式(创建型)
 *
 *      用原型实例指定创建对象的种类，并且通过拷贝这些原型创建新的对象。
 */
public class Client {

    /**
     * Client 客户角色：客户类提出创建对象的请求。
     * Prototype 抽象原型角色：这是一个抽象角色，通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
     * ConcretePrototype 具体原型角色：被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
     */
    /**
     *   1. 实现Cloneable接口。在java语言有一个Cloneable接口，它的作用只有一个，就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中，只有实现了这个接口的类才可以被拷贝，否则在运行时会抛出CloneNotSupportedException异常。
     *   2. 重写Object类中的clone方法。Java中，所有类的父类都是Object类，Object类中有一个clone方法，作用是返回对象的一个拷贝，但是其作用域protected类型的，一般的类无法调用，因此Prototype类需要将clone方法的作用域修改为public类型。
     */

    /**
     * use Prototype design : 主要是借助克隆实现的
     *    浅复制 —-只是拷贝了基本类型的数据，而引用类型数据，复制后也是会发生引用，我们把这种拷贝叫做“（浅复制）浅拷贝”，
     *            换句话说，浅复制仅仅是指向被复制的内存地址，如果原地址中对象被改变了，那么浅复制出来的对象也会相应改变。
     *
     *    深复制 —-在计算机中开辟了一块新的内存地址用于存放复制的对象。
     */
    /**
     * 浅度克隆
     *    创建一个新对象，新对象的属性和原来对象完全相同，对于非基本类型属性，仍指向原有属性所指向的对象的内存地址。
     * 　　只负责克隆按值传递的数据（比如基本数据类型、String类型），而不复制它所引用的对象，换言之，所有的对其他对象的引用都仍然指向原来的对象。
     *
     * 深度克隆
     *    创建一个新对象，属性中引用的其他对象也会被克隆，不再指向原有对象地址。
     * 　　除了浅度克隆要克隆的值外，还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象，而不再是原有的那些被引用的对象。
     *    换言之，深度克隆把要复制的对象所引用的对象都复制了一遍，而这种对被引用到的对象的复制叫做间接复制。
     *
     * 　　深度克隆要深入到多少层，是一个不易确定的问题。在决定以深度克隆的方式复制一个对象的时候，必须决定对间接复制的对象时采取浅度克隆还是继续采用深度克隆。
     *    因此，在采取深度克隆时，需要决定多深才算深。此外，在深度克隆的过程中，很可能会出现循环引用的问题，必须小心处理。
     *
     */
    public static void main(String[] args) {

        /**
         *  克隆对象与原对象不是同一个对象。
         *  克隆对象与原对象的类型一样。
         */

        try {
            // way 1:
            Prototype prototype = new Prototype();
            Prototype prototype1 = (Prototype) prototype.clone();
            System.out.println(prototype == prototype1);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        // way 2:
        IPrototype iPrototype = new ConcretePrototype();
        IPrototype iPrototype1 = (IPrototype) iPrototype.clone();
        System.out.println(iPrototype == iPrototype1);
    }
}
